#include <stdint.h>
#include <string.h>

#include "rtthread.h"

#include "fx_frame.h"

#include "fx_aperture.h"
#include "fx_zoom.h"

typedef enum
{
    FX_TR_STEP_NONE,
    FX_TR_STEP_STOP,
    FX_TR_STEP_BL_611,
    FX_TR_STEP_BL_411,
    FX_TR_STEP_BL_412,
    FX_TR_STEP_BL_621,
    FX_TR_STEP_BL_421,
    FX_TR_STEP_BL_422,
    FX_TR_STEP_APERTURE_READ,
    FX_TR_STEP_APERTURE_WRITE,
} fx_tr_step_t;

typedef enum
{
    FX_TR_EVENT_APERTURE_NOTIFY = (0x01 << 0),
    FX_TR_EVENT_APERTURE_CONFIG = (0x01 << 1),
} fx_tr_event_t;

struct rt_event FX_TR_EVENT;

static uint32_t FX_BL_611_WRITE_DATA[] = {0x00000820, 0x0C108002, 0x000009A6, 0x0D00881A, 0x00000000, 0x080089B8};
static uint32_t FX_BL_611_READ_DATA[ARRAY_LEN(FX_BL_611_WRITE_DATA)] = {0};
static uint32_t FX_BL_411_WRITE_DATA[] = {0x00000820, 0x0E108012, 0x00000000, 0x08008832};
static uint32_t FX_BL_411_READ_DATA[ARRAY_LEN(FX_BL_411_WRITE_DATA)] = {0};
static uint32_t FX_BL_412_WRITE_DATA[] = {0x00000820, 0x0F10801A, 0x00000000, 0x08008832};
static uint32_t FX_BL_412_READ_DATA[ARRAY_LEN(FX_BL_412_WRITE_DATA)] = {0};
static uint32_t FX_BL_621_WRITE_DATA[] = {0x00000820, 0x08108022, 0x000009A6, 0x0900883A, 0x00000000, 0x080089B8};
static uint32_t FX_BL_621_READ_DATA[ARRAY_LEN(FX_BL_621_WRITE_DATA)] = {0};
static uint32_t FX_BL_421_WRITE_DATA[] = {0x00000820, 0x0A108032, 0x00000000, 0x08008832};
static uint32_t FX_BL_421_READ_DATA[ARRAY_LEN(FX_BL_421_WRITE_DATA)] = {0};
static uint32_t FX_BL_422_WRITE_DATA[] = {0x00000820, 0x0B10803A, 0x00000000, 0x08008832};
static uint32_t FX_BL_422_READ_DATA[ARRAY_LEN(FX_BL_422_WRITE_DATA)] = {0};

static fx_frame_t FX_BLF_LIST[6] = {0};

// static fx_tr_step_t FX_TR_APERTURE_STEP = FX_TR_STEP_NONE;

void fx_blf_common4_prefix_callback(fx_frame_t *frame);
void fx_blf_common4_suffix_callback(fx_frame_t *frame);
void fx_blf_common6_prefix_callback(fx_frame_t *frame);
void fx_blf_common6_suffix_callback(fx_frame_t *frame);

int fx_bl_frame_init(void)
{
    for (size_t i = 0; i < ARRAY_LEN(FX_BLF_LIST); i++)
    {
        (FX_BLF_LIST + i)->data_interval_us = 1000;
        (FX_BLF_LIST + i)->prefix_delay_us = 0;
        (FX_BLF_LIST + i)->suffix_delay_us = 0;
    }

    FX_BLF_LIST[0].write_data = FX_BL_611_WRITE_DATA;
    FX_BLF_LIST[0].read_data = FX_BL_611_READ_DATA;
    FX_BLF_LIST[0].data_num = ARRAY_LEN(FX_BL_611_WRITE_DATA);
    FX_BLF_LIST[0].prefix_callback = fx_blf_common6_prefix_callback;
    FX_BLF_LIST[0].suffix_callback = fx_blf_common6_suffix_callback;

    FX_BLF_LIST[1].write_data = FX_BL_411_WRITE_DATA;
    FX_BLF_LIST[1].read_data = FX_BL_411_READ_DATA;
    FX_BLF_LIST[1].data_num = ARRAY_LEN(FX_BL_411_WRITE_DATA);
    FX_BLF_LIST[1].prefix_callback = fx_blf_common4_prefix_callback;
    FX_BLF_LIST[1].suffix_callback = fx_blf_common4_suffix_callback;

    FX_BLF_LIST[2].write_data = FX_BL_412_WRITE_DATA;
    FX_BLF_LIST[2].read_data = FX_BL_412_READ_DATA;
    FX_BLF_LIST[2].data_num = ARRAY_LEN(FX_BL_412_WRITE_DATA);
    FX_BLF_LIST[2].prefix_callback = fx_blf_common4_prefix_callback;
    FX_BLF_LIST[2].suffix_callback = fx_blf_common4_suffix_callback;

    FX_BLF_LIST[3].write_data = FX_BL_621_WRITE_DATA;
    FX_BLF_LIST[3].read_data = FX_BL_621_READ_DATA;
    FX_BLF_LIST[3].data_num = ARRAY_LEN(FX_BL_621_WRITE_DATA);
    FX_BLF_LIST[3].prefix_callback = fx_blf_common6_prefix_callback;
    FX_BLF_LIST[3].suffix_callback = fx_blf_common6_suffix_callback;

    FX_BLF_LIST[4].write_data = FX_BL_421_WRITE_DATA;
    FX_BLF_LIST[4].read_data = FX_BL_421_READ_DATA;
    FX_BLF_LIST[4].data_num = ARRAY_LEN(FX_BL_421_WRITE_DATA);
    FX_BLF_LIST[4].prefix_callback = fx_blf_common4_prefix_callback;
    FX_BLF_LIST[4].suffix_callback = fx_blf_common4_suffix_callback;

    FX_BLF_LIST[5].write_data = FX_BL_422_WRITE_DATA;
    FX_BLF_LIST[5].read_data = FX_BL_422_READ_DATA;
    FX_BLF_LIST[5].data_num = ARRAY_LEN(FX_BL_422_WRITE_DATA);
    FX_BLF_LIST[5].prefix_callback = fx_blf_common4_prefix_callback;
    FX_BLF_LIST[5].suffix_callback = fx_blf_common4_suffix_callback;

    return 0;
}

int fx_bl_init(void)
{
    fx_bl_frame_init();

    rt_event_init(&FX_TR_EVENT, "FX_TR", RT_IPC_FLAG_FIFO);

    return 0;
}
INIT_PREV_EXPORT(fx_bl_init);

void fx_blf_common4_prefix_callback(fx_frame_t *frame)
{
}

void fx_blf_common4_suffix_callback(fx_frame_t *frame)
{
    static uint32_t record = 0;

    if (record != frame->read_data[2])
    {
        rt_kprintf("status: 0x%08X\n", frame->read_data[2]);
        record = frame->read_data[2];
    }

    if ((frame->read_data[2] & 0xF0000000))
    {
        return;
    }

    if ((frame->read_data[2] & 0x00100000) == 0x00100000)
    {
        uint32_t aperture_value = 0;

        rt_thread_mdelay(1);

        fx_aperture_read(&aperture_value);
        rt_kprintf("aperture value: 0x%08X\n", aperture_value);
    }

    if ((frame->read_data[2] & 0x00080000) == 0x00080000)
    {
        rt_thread_mdelay(36);

        fx_zoom_read();
    }
}

void fx_blf_common6_prefix_callback(fx_frame_t *frame)
{
}

void fx_blf_common6_suffix_callback(fx_frame_t *frame)
{
}

void fx_base_loop(void)
{
    // rt_kprintf("%s\n", __FUNCTION__);

    rt_err_t ret;

    static uint32_t fx_tick = 0;
    static uint32_t fx_lb_index = 0;

    uint32_t tick_current = rt_tick_get();

    if (tick_current - fx_tick >= 40)
    {
        fx_frame_execute(FX_BLF_LIST + fx_lb_index);
        fx_lb_index += 1;

        if (fx_lb_index == 6)
        {
            fx_lb_index = 0;
        }

        fx_tick = tick_current;

        if (fx_lb_index == 1)
        {
            ret = rt_event_recv(&APERTURE_EVENT, FX_APERTURE_EVENT_WRITE_REQUEST,
                                RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0, NULL);
            if (ret == RT_EOK)
            {
                rt_thread_mdelay(2);

                fx_aperture_write(FX_APERTURE_WRITE_VALUE);

                rt_event_send(&APERTURE_EVENT, FX_APERTURE_EVENT_WRITE_DONE);
            }
        }

        if (fx_lb_index == 2)
        {
            ret = rt_event_recv(&APERTURE_EVENT, FX_APERTURE_EVENT_READ_REQUEST, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
                                0, NULL);
            if (ret == RT_EOK)
            {
                rt_thread_mdelay(1);

                fx_aperture_read(&FX_APERTURE_READ_VALUE);

                rt_event_send(&APERTURE_EVENT, FX_APERTURE_EVENT_READ_DONE);
            }
        }
    }

    rt_thread_mdelay(1);
}
